﻿#include "Player.h"
#include "Animation.h"
#include "Timer.h"

Player::Player(bool facing_right)
{
	is_faceing_right = facing_right;

	animation_idle_left = new Animation();
	animation_idle_right = new Animation();
	animation_run_left = new Animation();
	animation_run_right = new Animation();
	animation_attack_ex_left = new Animation();
	animation_attack_ex_right = new Animation();
	animation_die_left = new Animation();
	animation_die_right = new Animation();

	timer_attack_cd = new Timer();
	timer_attack_cd->Set_Wait_Time(attack_cd);
	timer_attack_cd->Set_One_Shot(true);
	timer_attack_cd->Set_Callback([&]() {can_attack = true; });

	timer_invulnerable = new Timer();
	timer_invulnerable->Set_Wait_Time(750);
	timer_invulnerable->Set_One_Shot(true);
	timer_invulnerable->Set_Callback([&]() { is_invulnerable = false; });

	timer_invulnerable_blink = new Timer();
	timer_invulnerable_blink->Set_Wait_Time(75);
	timer_invulnerable_blink->Set_Callback([&]() { is_showing_sketch_frame = !is_showing_sketch_frame; });

	current_animation = is_faceing_right ? animation_idle_right : animation_idle_left;

	timer_run_effect_generation = new Timer();
	timer_run_effect_generation->Set_Wait_Time(75);
	timer_run_effect_generation->Set_Callback([&]()
		{
			Vector2 particle_position;
			IMAGE* frame = atlas_run_effect.get_image(0);
			particle_position.x = position.x + (size.x - frame->getwidth()) / 2;
			particle_position.y = position.y + size.y - frame->getheight();
			Particles.emplace_back(particle_position, &atlas_run_effect, 45);
		});

	timer_die_effect_generation = new Timer();
	timer_die_effect_generation->Set_Wait_Time(35);
	timer_die_effect_generation->Set_Callback([&]()
		{
			Vector2 particle_position;
			IMAGE* frame = atlas_run_effect.get_image(0);
			particle_position.x = position.x + (size.x - frame->getwidth()) / 2;
			particle_position.y = position.y + size.y - frame->getheight();
			Particles.emplace_back(particle_position, &atlas_run_effect, 150);
		});

	animation_jump_effect = new Animation();
	animation_land_effect = new Animation();

	animation_jump_effect->Set_Atlas(&atlas_jump_effect);
	animation_jump_effect->Set_interval(25);
	animation_jump_effect->Set_loop(false);
	animation_jump_effect->Set_callback([&]() { is_jump_effect_visible = false; });

	animation_land_effect->Set_Atlas(&atlas_land_effect);
	animation_land_effect->Set_interval(50);
	animation_land_effect->Set_loop(false);
	animation_land_effect->Set_callback([&]() { is_land_effect_visible = false; });

	timer_cursor_visibility = new Timer();
	timer_cursor_visibility->Set_Wait_Time(2500);
	timer_cursor_visibility->Set_One_Shot(true);
	timer_cursor_visibility->Set_Callback([&]() { is_cursor_visible = false; });

	
}

void Player::on_update(int delta)
{
	int direction = is_right_key_down - is_left_key_down;

	if (direction != 0)
	{
		if(!is_attacking_ex)
			is_faceing_right = direction > 0;
		current_animation = is_faceing_right ? animation_run_right : animation_run_left;
		float distance = direction * run_velocity * delta;
		on_run(distance);
	}
	else
	{
		current_animation = is_faceing_right ? animation_idle_right : animation_idle_left;
		timer_run_effect_generation->Pause();
	}
	if (is_attacking_ex)
		current_animation = is_faceing_right ? animation_attack_ex_right : animation_attack_ex_left;
	if (Hp <= 0)
		current_animation = last_hurt_direction.x < 0 ? animation_die_left : animation_die_right;
	animation_jump_effect->Update(delta);
	animation_land_effect->Update(delta);
	current_animation->Update(delta);

	timer_attack_cd->on_update(delta);
	timer_invulnerable->on_update(delta);
	timer_invulnerable_blink->on_update(delta);
	timer_run_effect_generation->on_update(delta);
	timer_cursor_visibility->on_update(delta);

	if (Hp <= 0)
		timer_die_effect_generation->on_update(delta);
	Particles.erase(std::remove_if(
		Particles.begin(), Particles.end(),
		[](const Particle& particle)
		{
			return !particle.check_valid();
		}), Particles.end());

	for ( Particle& particle : Particles)
		particle.on_update(delta);

	if (is_showing_sketch_frame)
		sketch_image(current_animation->Get_frame(), &img_sketch);

	move_and_collide(delta);
}

void Player::on_draw(const Camera& camera)
{
	if (is_jump_effect_visible)
		animation_jump_effect->On_draw(camera, position_jump_effect.x, position_jump_effect.y);
	if(is_land_effect_visible)
		animation_land_effect->On_draw(camera, position_land_effect.x, position_land_effect.y);
	for ( Particle& particle : Particles)
		particle.on_draw(camera);

	if (Hp > 0 && is_invulnerable && is_showing_sketch_frame)
		putimage_lapha(camera, (int)position.x, (int)position.y, &img_sketch);
	else
		current_animation->On_draw(camera, (int)position.x, (int)position.y);

	if (is_cursor_visible)
	{
		switch (id)
		{
		case PlayerID::P1:
			putimage_lapha(camera, (int)(position.x + (size.x - img_lP_cursor.getwidth()) / 2),
				(int)(position.y - img_lP_cursor.getheight()), &img_lP_cursor);
			break;
		case PlayerID::P2:
			putimage_lapha(camera, (int)(position.x + (size.x - img_2P_cursor.getwidth()) / 2),
				(int)(position.y - img_2P_cursor.getheight()), &img_2P_cursor);
			break;
		}
	}

	if (is_debug)
	{
		setlinecolor(RGB(0, 125, 255));
		rectangle((int)position.x, (int)position.y, (int)(position.x + size.x), (int)(position.y + size.y));
	}
}

void Player::on_input(const ExMessage& msg)
{
	switch (msg.message)
	{
	case WM_KEYDOWN:
		switch (id)
		{
		case PlayerID::P1:
			switch (msg.vkcode)
			{
			case 0x41://A
				is_left_key_down = true;
				break;
			case 0x44://D
				is_right_key_down = true;
				break;
			case 0x57://W
				on_jump();
				break;
			case 0x46://F
				if (can_attack)
				{
					on_attack();
					can_attack = false;
					timer_attack_cd->Restart();
				}
				break;
			case 0x47://G
				if (Mp>=100)
				{
					on_attack_ex();
					Mp = 0;
				}
				break;
			}
			break;
		case PlayerID::P2:
			switch (msg.vkcode)
			{
			case VK_LEFT://小键盘左
				is_left_key_down = true;
				break;
			case VK_RIGHT://小键盘右
				is_right_key_down = true;
				break;
			case VK_UP://小键盘上
				on_jump();
				break;
			case VK_NUMPAD1://小键盘1
				if (can_attack)
				{
					on_attack();
					can_attack = false;
					timer_attack_cd->Restart();
				}
				break;
			case VK_NUMPAD2://小键盘2
				if (Mp >= 100)
				{
					on_attack_ex();
					Mp = 0;
				}
				break;
			}
			break;
		}
		break;
	case WM_KEYUP:
		switch (id)
		{
		case PlayerID::P1:
			switch (msg.vkcode)
			{
			case 0x41://A
				is_left_key_down = false;
				break;
			case 0x44://D
				is_right_key_down = false;
				break;
			}
			break;
		case PlayerID::P2:
			switch (msg.vkcode)
			{
			case VK_LEFT://小键盘左
				is_left_key_down = false;
				break;
			case VK_RIGHT://小键盘右
				is_right_key_down = false;
				break;
			}
			break;
		}
		break;
	}
}

void Player::on_run(float distance)
{
	if (is_attacking_ex) return;
	position.x += distance;

	timer_run_effect_generation->Resume();
}

void Player::on_jump()
{
	if (velocity.y != 0|| is_attacking_ex) return;
	velocity.y += jump_velocity;

	is_jump_effect_visible = true;
	animation_jump_effect->Reset();

	IMAGE* effect_frame = animation_jump_effect->Get_frame();
	position_jump_effect.x = position.x + (size.x - effect_frame->getwidth()) / 2;
	position_jump_effect.y = position.y + size.y - effect_frame->getheight();
}

void Player::move_and_collide(int delta)
{
	float last_velocity_y = velocity.y;
	velocity.y += gravity * delta;
	position += velocity * (float)delta;

	if (Hp <= 0)
		return;
	if (velocity.y > 0)
	{
		for (const Platform& platform : Platforms)
		{
			const Platform::CollisionShape& shape = platform.shape;
			//判断X轴上是否碰撞
			bool is_collied_x = (max(position.x + size.x, shape.right) - min(position.x, shape.left)
				<= size.x + (shape.right - shape.left));
			//判断Y轴上是否碰撞
			bool is_collied_y = (shape.y >= position.y && shape.y <= position.y + size.y);

			if (is_collied_y&&is_collied_x)
			{
				float delta_pos_y = velocity.y * delta;								//计算在上帧内Y轴上移动的距离
				float last_tick_foot_pos_y = position.y + size.y - delta_pos_y;		//计算在上帧内玩家图片最下方位置

				if (last_tick_foot_pos_y<= shape.y)
				{
					position.y = shape.y - size.y;
					velocity.y = 0;

					if (last_velocity_y != 0)
						on_land();

					break;
				}
			}
		}
	}
	if (!is_invulnerable) 
	{
		for (Bullet* bullet : Bullets)
		{
			if (!bullet->get_valid() || bullet->get_collied_target() != id)
				continue;

			if (bullet->check_collied(position,size))
			{
				make_invulnerable();
				bullet->on_collied();
				bullet->set_valid(false);
				Hp -= bullet->get_damage();
				last_hurt_direction = bullet->get_position() - position;
				if (Hp <= 0)
				{
					velocity.x = last_hurt_direction.x < 0 ? 0.35f : -0.35;
					velocity.y = -1.f;
				}
			}
		}
	}
}

void Player::make_invulnerable()
{
	is_invulnerable = true;
	timer_invulnerable->Restart();
}

void Player::on_land()
{
	is_land_effect_visible = true;
	animation_land_effect->Reset();

	IMAGE* effect_frame = animation_land_effect->Get_frame();
	position_land_effect.x = position.x + (size.x - effect_frame->getwidth()) / 2;
	position_land_effect.y = position.y + size.y - effect_frame->getheight();
}
